當開始有標籤專屬頁面後,這時候就會更近一步想要有一個標籤列表,讓我知道 Digital Garden 上有哪些標籤、各有多少文章。今天就來建立標籤清單的頁面吧!
首先,先建立 @/pages/tags/index.vue
,並且輸入範例程式碼。今天的範例程式碼還沒精簡過,為了方便閱讀,就將 <template />
和 <script />
分開檢視吧。
<template>
<div>
<div
class="flex flex-row divide-gray-200 mt-24 items-center justify-center space-x-6 divide-y-0"
>
<div class="space-x-2 pt-6 pb-8 space-y-5">
<h1
class="font-extrabold leading-9 tracking-tight text-gray-900 border-r-2 px-6 text-6xl leading-14"
>
Tags
</h1>
</div>
<ul class="flex max-w-lg flex-wrap list-none">
<li v-for="tag in articleTags" :key="tag" class="mt-2 mb-2 mr-5 no-underline">
<PostTag :text="tag" />
<NuxtLink
:href="'/tags/' + kebabCase(tag)"
class="-ml-2 text-sm font-semibold uppercase text-gray-600 no-underline"
aria-label="
posts
tagged
${tag}`"
>
({{ tagsCount[tag] }})
</NuxtLink>
</li>
</ul>
</div>
</div>
</template>
在 Template 部分,透過 TailwindCSS 的 Flex Direction 將頁面做點變化,讓標題與標籤清單並列在同一個水平上,這樣在當前標籤還不多時,比較不會有單薄的感覺。
並遍歷 articleTags
這個變數,產生一系列的標籤項目,在標籤項目中我們複用了在 Article
中有用到的 PostTag
元件,並在旁邊新增其數量,數量則取自於 tagsCount
這個物件。
<script setup>
import { kebabCase, toLower } from 'lodash-es/string'
const tagsCount = {}
// [TODO]: extract to composable
const flatten = (tagsList, key) => {
const _tags = tagsList
.map((element) => {
let _e = element
const whenElementIsPost = typeof element === 'object'
if (whenElementIsPost) {
if (!element[key]) {
element[key] = []
}
const tags = element[key]
const flattened = flatten(tags)
_e = flattened
}
const whenElementIsTag = typeof key === 'undefined'
if (whenElementIsTag) {
const tag = toLower(_e)
tagsCount[tag] = tagsCount[tag] ? tagsCount[tag] + 1 : 1
_e = tag
}
return _e
})
.flat(1)
return _tags
}
const { data } = await useAsyncData('tags', () =>
queryContent('/articles')
.only(['tags'])
.where({ tags: { $exists: true } })
.where({ published_at: { $ne: null } })
.find()
)
const flat = [...new Set(flatten(data.value, 'tags'))]
const articleTags = flat.filter((tag) => {
return typeof tag === 'string' && tag.length > 0
})
</script>
在程式碼的部分,先透過查詢方法取得每一篇文章,並且透過 where()
限定擁有 tags
屬性的文章。另外比較有趣的部分是,透過 only()
來只取得其 tags 屬性,來節省空間使用。
接著利用上面宣告的 flatten()
函式,協助我們將這些文章的 tags 屬性扁平化,建立一個不重複的 tags 清單。並在之中協助計算 tags 在多少文章出現過,並將數量記錄在前面用到的 tagsCount
物件。
成果如圖: